package service

import (
	"errors"
	"regexp"

	"bbs/pkg/domain"
	"bbs/pkg/model/encrypt"

	"github.com/go-playground/validator/v10"
)

type userService struct {
	userRepo   domain.UserRepository
	captchaSvc domain.CaptchaService
}

func NewUserService(userRepo domain.UserRepository, captchaSvc domain.CaptchaService) domain.UserService {
	return &userService{
		userRepo:   userRepo,
		captchaSvc: captchaSvc,
	}
}

func (svc *userService) CheckUser(regUser *domain.ResiterUser) error {
	// check password
	if regUser.Password != regUser.RePassword {
		return errors.New("the two password entered are not the same")
	}

	if _, err := svc.userRepo.GetUserByName(regUser.Name); err == nil {
		return errors.New("user already exist")
	}

	if _, err := svc.userRepo.GetUserByEmail(regUser.Email); err == nil {
		return errors.New("email address already registered ")
	}

	// validate user filed
	validate := validator.New()
	validate.RegisterValidation("match", func(fl validator.FieldLevel) bool {
		ok, _ := regexp.MatchString("^[a-zA-Z0-9_-]{4,16}$", fl.Field().String())
		return ok
	})

	return validate.Struct(regUser)
}

func (svc *userService) CreateUser(regUser *domain.ResiterUser) error {
	user := &domain.User{
		Name:     regUser.Name,
		Email:    regUser.Email,
		Password: encrypt.Md5Encrypt(regUser.Password),
	}

	return svc.userRepo.CreateUser(user)
}

func (svc *userService) AuthenticateUser(loginUser *domain.LoginUser) (*domain.User, error) {
	validate := validator.New()
	validate.RegisterValidation("match", func(fl validator.FieldLevel) bool {
		match, _ := regexp.MatchString("^[a-zA-Z0-9_-]{4,16}$", fl.Field().String())
		return match
	})

	if err := validate.Struct(loginUser); err != nil {
		return nil, err
	}

	if err := validate.Var(loginUser.Account, "email"); err == nil {
		user, err := svc.userRepo.GetUserByEmail(loginUser.Account)
		if err != nil {
			return nil, err
		}
		if encrypt.Md5Encrypt(loginUser.Password) != user.Password {
			return nil, errors.New("username or password error")
		}
		return user, nil
	}

	if err := validate.Var(loginUser.Account, "match"); err == nil {
		user, err := svc.userRepo.GetUserByName(loginUser.Account)
		if err != nil {
			return nil, err
		}
		if encrypt.Md5Encrypt(loginUser.Password) != user.Password {
			return nil, errors.New("username or password error")
		}
		return user, nil
	}

	return nil, errors.New("invalid login message")
}

func (svc *userService) GetUserByID(userID string) (*domain.User, error) {
	return svc.userRepo.GetUserByID(userID)
}

func (svc *userService) UpdateUser(user *domain.User) error {
	return svc.userRepo.UpdateUser(user)
}

func (svc *userService) GetUserByEmail(email string) (*domain.User, error) {

	return svc.userRepo.GetUserByEmail(email)
}

func (svc *userService) Send(email string) error {
	if err := svc.captchaSvc.SendByEmail(email); err != nil {
		return err
	}
	return nil
}

func (svc *userService) ResetPassword(reseting *domain.Reseting) error {
	user, err := svc.GetUserByEmail(reseting.Email)
	if err != nil {
		return err
	}

	user.Password = encrypt.Md5Encrypt(reseting.New_Password)

	return svc.userRepo.UpdateUser(user)
}
